home *** CD-ROM | disk | FTP | other *** search
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define TRIANGLE 1
- #define MESH 2
- #define ERROR -1
- #define VERSION 1
- #define INCREMENT 1
- #define EMAIL_ADDRESS "abw@oasis.icl.co.uk"
-
-
- /*
- * geodome.c
- *
- * (C) 1994 Andy Wardley (abw@oasis.icl.co.uk). All Rights Reserved.
- *
- * maths libraray is required.
- * getopt must be provided.
- *
- */
-
-
- struct vertex { double x, y, z; };
- struct triangle { struct vertex a, b, c; };
-
- struct edge
- {
- struct vertex a, b;
- struct edge *next;
- };
-
- struct joint
- {
- struct vertex v;
- struct joint *next;
- };
-
-
- /* default options */
- int mode = TRIANGLE;
- int rec_depth = 3;
- double pipe_radius = 0.01;
- double joint_radius = 0.015;
- double geodome_radius = 1;
-
-
- /* heads of linked lists */
- struct edge *first_edge;
- struct joint *first_joint;
-
-
- /* print usage message */
- void usage(void)
- {
- printf("GEODOME V%d.%d Geodome generator for POV-Ray V2.n 23-01-94\n", VERSION, INCREMENT);
- printf("(C) 1994 Andy Wardley <%s>. All Rights Reserved\n\n", EMAIL_ADDRESS);
- printf("usage:\n\tgeodome [-r depth] [-t | -m [-p radius] [-j radius]]\n\n");
- printf("\t-r depth recursion depth (default: %i)\n", rec_depth);
- printf("\t-t generate triangles (default)\n");
- printf("\t-m generate pipe mesh\n");
- printf("\t-p radius pipe radius (mesh only) (default: %5.4f)\n", pipe_radius);
- printf("\t-j radius joint radius (mesh only) (default: %5.4f)\n", joint_radius);
- printf("\nGEODOME may be freely distributed provided it is in its\n");
- printf("original form and has not been modified in any way.\n");
- }
-
-
- char *basename(char *pathname)
- {
- char *ptr;
-
- if ((ptr = strrchr(pathname, '\\')) != NULL)
- return ptr + 1;
- else
- return NULL;
- }
-
-
-
- /* add a joint to the linked list */
- int add_joint(struct vertex *v)
- {
- struct joint *new_joint, *j;
-
- /* allocate memory for a new joint */
- if ((new_joint = (struct joint *) malloc (sizeof(struct joint)))
- == (struct joint *) NULL)
- {
- fprintf(stderr, "Out of memory\n");
- return 1;
- }
-
- /* load values and set fwd pointer to NULL */
- new_joint->v = *v;
- new_joint->next = (struct joint *) NULL;
-
- /* check for an empty list */
- if (first_joint == (struct joint *) NULL)
- first_joint = new_joint;
- else
- {
- j = first_joint;
-
- /* traverse existing linked list */
- for (;;)
- {
- /* forget duplicates */
- if (memcmp(&j->v, &new_joint->v, sizeof(struct vertex)) == 0)
- {
- free(new_joint);
- return 0;
- }
-
- /* if at end of list, add new joint */
- if (j->next == (struct joint *) NULL)
- {
- j->next = new_joint;
- return 0;
- }
-
- /* next list element */
- j = j->next;
- }
- }
-
- return 0;
- }
-
-
- /* add an edge to the linked list */
- int add_edge(struct vertex *a, struct vertex *b)
- {
- struct edge *new_edge, *e;
-
- /* allocate memory for a new joint */
- if ((new_edge = (struct edge *) malloc(sizeof(struct edge)))
- == (struct edge *) NULL)
- {
- fprintf(stderr, "Out of memory\n");
- return 1;
- }
-
- /*
- load the new structure with the data. We always make sure that
- new_edge->a gets the smaller value (reason given below)
- */
- if (memcmp(a, b, sizeof(struct vertex)) < 0)
- {
- new_edge->a = *a;
- new_edge->b = *b;
- }
- else
- {
- new_edge->a = *b;
- new_edge->b = *a;
- }
-
- /* set fwd pointer to NULL */
- new_edge->next = (struct edge *) NULL;
-
- /* check for an empty linked list */
- if (first_edge == (struct edge *) NULL)
- first_edge = new_edge;
- else
- {
- e = first_edge;
-
- /* traverse existing linked list */
- for (;;)
- {
- /*
- here we compare new element against existing
- list elements. If we find a match, we don't
- need to add it again. This is why we always
- put the smallest value in a, otherwise, we
- wouldn't find the match if the ends were swapped.
- */
- if (memcmp(&e->a, &new_edge->a, sizeof(struct vertex)) == 0
- && memcmp(&e->b, &new_edge->b, sizeof(struct vertex)) == 0)
- {
- free(new_edge);
- return 0;
- }
-
- /* add the edge if we've got to the end of the list */
- if (e->next == (struct edge *) NULL)
- {
- e->next = new_edge;
- return 0;
- }
-
- /* next list item */
- e = e->next;
- }
- }
-
- return 0;
- }
-
-
- /* add the three joints and edges for a given triangle */
- int add_triangle(struct triangle *t)
- {
- if (add_joint(&t->a) != 0)
- return ERROR;
- if (add_joint(&t->b) != 0)
- return ERROR;
- if (add_joint(&t->c) != 0)
- return ERROR;
- if (add_edge(&t->a, &t->b) != 0)
- return ERROR;
- if (add_edge(&t->b, &t->c) != 0)
- return ERROR;
- if (add_edge(&t->c, &t->a) != 0)
- return ERROR;
- }
-
-
- /* returns the mid-point of two vertices (extended to geodome radius) */
- struct vertex average(struct vertex *v1, struct vertex *v2)
- {
- struct vertex m;
- double hypot, ratio;
-
- m.x = (v1->x + v2->x) / 2;
- m.y = (v1->y + v2->y) / 2;
- m.z = (v1->z + v2->z) / 2;
-
- hypot = sqrt(pow(m.x, 2) + pow(m.y, 2) + pow(m.z, 2));
- ratio = geodome_radius / hypot;
-
- m.x *= ratio;
- m.y *= ratio;
- m.z *= ratio;
-
- return m;
- }
-
-
- /* sub-divide a triangle into 4 smaller triangles */
- void divide_triangle(struct triangle *t, int depth)
- {
- struct triangle new_t[4];
- int subt;
-
- new_t[0].a = t->a;
- new_t[1].b = t->b;
- new_t[2].c = t->c;
-
- new_t[0].c = new_t[2].a = new_t[3].b = average(&(t->a), &t->c);
- new_t[0].b = new_t[1].a = new_t[3].c = average(&t->a, &t->b);
- new_t[1].c = new_t[2].b = new_t[3].a = average(&t->c, &t->b);
-
- /* recurse if depth not yet reached */
- if (--depth != 0)
- for(subt = 0; subt < 4; subt++)
- divide_triangle(&new_t[subt], depth);
- else
- {
- /*
- dump triangle data or add to linked lists, depending
- on the type of geodome
- */
- for(subt = 0; subt < 4; subt++)
- {
- if (mode == TRIANGLE)
- printf("\ttriangle {\n\t\t<%.10f, %.10f, %.10f>\
- \n\t\t<%.10f, %.10f, %.10f>\n\t\t<%.10f, %.10f, %.10f>\n\t}\n",
- new_t[subt].a.x, new_t[subt].a.y, new_t[subt].a.z,
- new_t[subt].b.x, new_t[subt].b.y, new_t[subt].b.z,
- new_t[subt].c.x, new_t[subt].c.y, new_t[subt].c.z);
- else
- add_triangle(&new_t[subt]);
- }
- }
- }
-
-
-
- void main(int argc, char **argv)
- {
- char ch;
- struct triangle t;
- struct joint *j;
- struct edge *e;
-
- /* zero linked list */
- first_edge = NULL;
- first_joint = NULL;
-
- /* read command line */
- while ((ch = getopt(argc, argv, "tmr:p:j:")) != EOF)
- {
- switch(ch)
- {
- case 't':
- mode = TRIANGLE;
- break;
-
- case 'm':
- mode = MESH;
- break;
-
- case 'r':
- rec_depth = atoi(optarg);
- if (rec_depth == 0)
- {
- fprintf(stderr, "%s: invalid recursion depth\n",
- basename(argv[0]));
- exit(1);
- }
- break;
-
- case 'p':
- pipe_radius = atof(optarg);
- if (pipe_radius == 0)
- {
- fprintf(stderr, "%s: invalid pipe radius\n",
- basename(argv[0]));
- exit(1);
- }
- break;
-
- case 'j':
- joint_radius = atof(optarg);
- if (joint_radius == 0)
- {
- fprintf(stderr, "%s: invalid joint radius\n",
- basename(argv[0]));
- exit(1);
- }
- break;
-
- case '?':
- usage();
- exit(1);
- break;
- }
- }
-
- /* setup the parent triangle */
- t.a.x = t.b.x = 0;
- t.b.y = t.c.y = 0;
- t.a.z = t.c.z = 0;
- t.c.x = geodome_radius;
- t.a.y = geodome_radius;
- t.b.z = geodome_radius;
-
- /* print some stats */
- fprintf(stderr, "recursion depth: %i\n", rec_depth);
- fprintf(stderr, " mode: %s\n", mode == TRIANGLE ? "triangles" : "mesh");
- if (mode == MESH)
- {
- fprintf(stderr, " pipe radius: %5.4f\n", pipe_radius);
- fprintf(stderr, " joint radius: %5.4f\n", joint_radius);
- }
-
-
- printf("/* model data created by geodome V%d.%d */\n", VERSION, INCREMENT);
- printf("/* by Andy Wardley <%s> */\n\n", EMAIL_ADDRESS);
- printf("#declare geodome_eighth =\nunion {\n");
- divide_triangle(&t, rec_depth);
-
- if (mode == MESH)
- {
- printf("//\tjoints\n");
-
- /* traverse joint list, printing and free as we go */
- while (first_joint != (struct joint *) NULL)
- {
- j = first_joint;
- first_joint = first_joint->next;
- printf("\tsphere { <%.10f, %.10f, %.10f> %5.4f }\n",
- j->v.x, j->v.y, j->v.z, joint_radius);
- free(j);
- }
-
- printf("\n//\tedges\n");
-
- /* traverse edge list, printing and freeing as we go */
- while (first_edge != (struct edge *) NULL)
- {
- e = first_edge;
- first_edge = first_edge->next;
- printf("\tcone {\n");
- printf("\t\t<%.10f, %.10f, %.10f> %5.4f\n",
- e->a.x, e->a.y, e->a.z, pipe_radius);
- printf("\t\t<%.10f, %.10f, %.10f> %5.4f\n\t}\n",
- e->b.x, e->b.y, e->b.z, pipe_radius);
- free(e);
- }
- }
-
- printf("}\n");
-
- /* finally create some complete geodome hemispheres and spheres */
- printf("\n\n#declare geodome_hemisphere = \nunion {\n");
- printf("\tobject { geodome_eighth }\n");
- printf("\tobject { geodome_eighth rotate <0, 90, 0> }\n");
- printf("\tobject { geodome_eighth rotate <0, 180, 0> }\n");
- printf("\tobject { geodome_eighth rotate <0, 270, 0> }\n");
- printf("}\n");
-
- printf("\n\n#declare geodome = \nunion {\n");
- printf("\tobject { geodome_hemisphere }\n");
- printf("\tobject { geodome_hemisphere rotate <180, 0, 0> }\n");
- printf("}\n");
- }
-
-